#include "FolderDataSource.h"
#include "DataSource.h"

FolderDataSource::FolderDataSource(const std::filesystem::path& folderPath) : folderPath_(folderPath), listfile_{} {
    try {
        for (const auto& entry : std::filesystem::recursive_directory_iterator(folderPath_)) {
            if (entry.is_regular_file()) {
                listfile_.insert(entry.path().string());
            }
        }
    }
    catch (const std::exception& e) {
        throw std::runtime_error(e.what());
    }
}

std::shared_ptr<DataSource> FolderDataSource::createDataSource() {
    return std::make_shared<DataSource>(*this);
}

std::string FolderDataSource::getDisplayName() const {
    return "Folder Data Source";
}

std::set<std::string> FolderDataSource::getListfile() const {
    return listfile_;
}

bool FolderDataSource::has(const std::string& filepath) const {
    if (filepath.empty()) {
        return false; // special case for folder data source, dont do this
    }
    const auto resolvedPath = folderPath_ / filepath;
    return std::filesystem::exists(resolvedPath) && !std::filesystem::is_directory(resolvedPath);
}

std::filesystem::path FolderDataSource::getDirectory(const std::string& filepath) const {
    const auto resolvedPath = folderPath_ / filepath;
    if (!std::filesystem::exists(resolvedPath)) {
        return {};
    }
    if (std::filesystem::is_directory(resolvedPath)) {
        return resolvedPath;
    }
    else {
        return {};
    }
}

std::vector<uint8_t> FolderDataSource::read(const std::string& path) const {
    const auto resolvedPath = folderPath_ / fixFilepath(path);
    if (!std::filesystem::exists(resolvedPath)) {
        return {};
    }
    return std::vector<uint8_t>(std::filesystem::ifstream(resolvedPath));
}

std::shared_ptr<DataSource> FolderDataSource::getResourceAsStream(const std::string& filepath) const {
    const auto resolvedPath = folderPath_ / fixFilepath(filepath);
    if (!has(filepath)) {
        return {};
    }
    return std::make_shared<FolderDataSource>(*this, resolvedPath.string());
}

void* FolderDataSource::getFile(const std::string& filepath) const {
    const auto resolvedPath = folderPath_ / fixFilepath(filepath);
    if (!std::filesystem::exists(resolvedPath)) {
        return nullptr;
    }
    return new void* [1] {resolvedPath.c_str()};
}

std::string FolderDataSource::fixFilepath(const std::string& filepath) const {
    return filepath.replace('\\', '/').replace(':', '/');
}
